/*
 * Copyright (C) Pietro Pilolli 2010 <pilolli.pietro@gmail.com>
 * 
 * Curtain is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Curtain is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "callbacks.h"
#include "utils.h"


/* The main cairo context; will used to draw the window. */
static cairo_t *cr = (cairo_t *) NULL;

/* Shape cairo context; will used to draw the shape. */
static cairo_t *shape_cr = (cairo_t *) NULL;

/* The bitmap used to shape the window. */
static GdkBitmap *shape = (GdkBitmap *) NULL;

/* The surface will have the same dimension of the screen and will contain the curtain. */
static cairo_surface_t *scaled_surface = (cairo_surface_t *) NULL;

/* Variables where will store the coordinates of the press point. */
static gdouble press_event_x = 0.0;
static gdouble press_event_y = 0.0;

/* These points identify the area with the painted curtain. */
static gdouble min_x = 0.0;
static gdouble max_x = 0.0;
static gdouble min_y = 0.0;
static gdouble max_y = 0.0;

static gint screen_width = 0;
static gint screen_height = 0;


/* Quit the program. */
static void
quit ()
{
  if (shape)
    {
      g_object_unref (G_OBJECT (shape));
    }
  if (cr)
    {
      cairo_destroy (cr);
    }
  if (shape_cr)
    {
      cairo_destroy (shape_cr);
    }
  if (scaled_surface)
    {
      cairo_surface_destroy (scaled_surface);
    }
  gtk_main_quit ();
  exit (1);
}


/* Paint the white cross to be clicked in order to close the program. */
static void
paint_cross ()
{
  if (cr)
    { 
      gint delta = 25;
      gchar *color = "FFFFFFFF";

      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
      cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
      cairo_set_source_color_from_string (cr, color);
      cairo_rectangle (cr, (max_x - delta), min_y, delta, delta);	
      cairo_move_to (cr, (max_x - delta), min_y);
      cairo_line_to (cr, max_x, (min_y + delta));
      cairo_move_to (cr, max_x, min_y);
      cairo_line_to (cr, (max_x - delta), (min_y + delta));
      cairo_stroke (cr);
    }
}


/* Paint the curtain in the window. */
static void
paint_curtain ()
{
  if (cr)
    { 
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_surface (cr, scaled_surface, 0, 0);
      cairo_rectangle (cr, min_x, min_y, max_x, max_y);
      cairo_fill (cr);
      cairo_stroke (cr);
    }
}


/* Reset the shape. */
static void
reset_shape ()
{
  if (shape_cr)
    { 
      cairo_set_operator (shape_cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_rgba (shape_cr, 1, 1, 1, 1);
      cairo_paint (shape_cr);
    }
}


/* Paint a transparent rectangle on the window. */
static void
paint_transparent_rectangle (gdouble x, gdouble y, gdouble width, gdouble height)
{
  if (cr)
    {
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_rgba (cr, 0, 0, 0, 0);
      cairo_rectangle (cr, x, y, width, height);
      cairo_fill (cr);
    }	
  if (shape_cr)
    {
      cairo_set_operator (shape_cr,CAIRO_OPERATOR_SOURCE);
      cairo_set_source_rgba (shape_cr, 0, 0, 0, 0);
      cairo_rectangle (shape_cr, x, y, width, height);
      cairo_fill (shape_cr);	
    }	
}


/* Destroy window callback. */
G_MODULE_EXPORT gboolean 
destroy (GtkWidget *widget, gpointer data)
{
  quit ();
  return TRUE;
}


/* Expose event: this occurs when the windows is exposed. */
G_MODULE_EXPORT gboolean 
on_window_expose_event (GtkWidget *widget,
			GdkEventExpose *event,
			gpointer user_data)
{
  gint is_fullscreen = gdk_window_get_state (widget->window) & GDK_WINDOW_STATE_FULLSCREEN;
  if (is_fullscreen)
    {
      if (! scaled_surface)
	{
          cairo_surface_t *surface = cairo_image_surface_create_from_png (CURTAIN_FILE);

	  screen_width = gdk_screen_width ();
	  screen_height = gdk_screen_height ();
	  max_x = screen_width;
	  max_y = screen_height;
	  cr = gdk_cairo_create (widget->window);

          scaled_surface = scale_surface (surface, screen_width, screen_height);
          cairo_surface_destroy (surface);
	  
	  shape = gdk_pixmap_new (NULL, screen_width, screen_height, 1);
	  shape_cr = gdk_cairo_create (shape);
	  paint_curtain ();
	  paint_cross ();
	}
    }
  return TRUE;
}


/* Destroy callback. */
G_MODULE_EXPORT gboolean 
on_window_destroy_event (GtkWindow *self, GdkEvent *event, gpointer user_data)
{
  quit ();
  return TRUE;
}


/* On press callback. */
G_MODULE_EXPORT gboolean 
on_window_button_press_event (GtkWindow *window, GdkEventButton *event, gpointer data)
{
  /* only button1 allowed */
  if (event->button != 1)
    {
      return FALSE;
    }
  /* Is inside the close pseudo button. */
  if (((event->x) > (max_x - 25)) &&
      ((event->y) < (min_y + 25)))
    {
      quit ();
    }
#ifndef _WIN32
  gtk_widget_input_shape_combine_mask (GTK_WIDGET (window), NULL, 0, 0);
#else
  /* grab mouse */
  grab_pointer (GTK_WIDGET (window), CURTAIN_MOUSE_EVENTS);
#endif
  reset_shape();
  press_event_x = event->x;
  press_event_y = event->y;
  return TRUE;
}


/* Release callback. */
G_MODULE_EXPORT gboolean
on_window_button_release_event (GtkWindow *window, GdkEventButton *event, gpointer data)
{
  gdouble delta_x = fabs (press_event_x-event->x);
  gdouble delta_y = fabs (press_event_y-event->y);

  gint min_curtain_width = 25;
  gint min_curtain_height = 25;

  /* only button1 allowed and ignore null event */
  if ((! event) || (event->button != 1))
    {
      return FALSE;
    }

  if (delta_y <= delta_x)
    {
      /* move on x axis */
      if (event->x >= press_event_x)
	{
	  /* Right gesture */
	  if ((press_event_x < (max_x + min_x)/2) && ( event->x <= max_x))
	    {
	      /* sx to the curtain ->| */
	      if (event->x > min_x)
		{
		  /* move right of delta_x */
		  //printf("->|\n");
		  min_x = event->x;
		  if (min_x > max_x-min_curtain_width)
		    {
		      min_x = max_x-min_curtain_width;
		    }
		  paint_transparent_rectangle (0, 0, min_x, screen_height);
		  paint_transparent_rectangle (max_x, 0, screen_width-max_x, screen_height);
		}
	    }
	  else
	    {
	      /* dx to the curtain |-> */
	      if (event->x > max_x)
		{
		  //printf("|->\n");
		  paint_transparent_rectangle (event->x, 0, screen_width-event->x, screen_height);
		  max_x = event->x;
		  if (max_x > screen_width)
		    {
		      max_x = screen_width;
		    }
		  paint_transparent_rectangle (0, 0, min_x, screen_height);
		}
	    }
	}
      else
	{
	  /* Left gesture */
	  if ((press_event_x > (max_x + min_x)/2) && (event->x >= min_x))
	    {
	      /* dx to curtain |<- */
	      if (event->x < max_x)
		{
		  /* move left */
		  //printf("|<-\n");
		  max_x = event->x;	
		  if(max_x-min_x < min_curtain_width)
		    {
		      max_x = min_x + min_curtain_width;
		    }
		  paint_transparent_rectangle (max_x, 0, (screen_width - max_x), screen_height);
		  paint_transparent_rectangle (0, 0, min_x, screen_height);
		}
	    }
	  else
	    {
	      /* sx to curtain <-| */
	      if (event->x < min_x)
		{
		  //printf(" <-|\n");
		  paint_transparent_rectangle (0, 0, event->x, screen_height);
		  min_x = event->x;	
		  if ((max_x - min_x) < min_curtain_width)
		    {
		      max_x = min_x + min_curtain_width;
		    }
		  paint_transparent_rectangle (max_x, 0, (screen_width - max_x), screen_height);
		}
	    }
	}	
      if (min_y > 0)
	{
	  paint_transparent_rectangle (0, 0, screen_width, min_y);
	}
      if (max_y < screen_height)
	{
	  paint_transparent_rectangle (0, max_y, screen_width, (screen_height - max_y));
	}
    }
  else
    {
      /* move on y axis */
      if (event->y >= press_event_y)
	{
	  /* down gesture */
	  if ((press_event_y < (max_y + min_y)/2) && (event->y <= max_y))
	    {
	      if (event->y > min_y)
		{
		  /* up half */
		  min_y = event->y;
		  if (min_y > (max_y - min_curtain_height))
		    {
		      min_y = max_y - min_curtain_height;
		    }
		  paint_transparent_rectangle (0, 0, screen_width, min_y);
		  paint_transparent_rectangle (0, max_y, screen_width, (screen_height - max_y));
		}
	    }
	  else
	    {
	      if (event->y > max_y)
		{
		  /* down half */
		  paint_transparent_rectangle (0, event->y, screen_width, (screen_height - event->y));
		  max_y = event->y;
		  if (max_y > screen_height)
		    {
		      max_y = screen_height;
		    }
		  paint_transparent_rectangle (0, 0, screen_width, min_y);
		}
	    }
	}
      else
	{
	  /* up gesture */
	  if ((press_event_y < (max_y + min_y)/2) || (event->y < min_y))
	    {
	      if (event->y < min_y)
		{
		  /* up half */
		  //printf("down gesture in first half\n");						
		  min_y = event->y;
		  if (min_y > (max_y - min_curtain_height))
		    {
		      min_y = max_y - min_curtain_height;
		    }
		  paint_transparent_rectangle (0, 0, screen_width, min_y);
		  paint_transparent_rectangle (0, max_y, screen_width, screen_height - max_y);
		}
	    }
	  else
	    {
	      if (event->y < max_y)
		{
		  /* down half */
		  //printf("down gesture in second half\n");
		  max_y = event->y;
		  if((max_y - min_y) < min_curtain_height)
		    {
		      max_y = min_y + min_curtain_height;
		    }
		  paint_transparent_rectangle (0, max_y, screen_width, (screen_height - max_y));
		  paint_transparent_rectangle (0, 0, screen_width, min_y);
		}
	    }
	}
      if (min_x > 0)
	{
	  paint_transparent_rectangle (0, 0, min_x, screen_height);
	}
      if (max_x < screen_width)
	{
	  paint_transparent_rectangle (max_x, 0, (screen_width - max_x), screen_height);
	}

    }
#ifndef _WIN32
  gtk_widget_input_shape_combine_mask (GTK_WIDGET (window), shape, 0, 0);
#else
  gtk_widget_shape_combine_mask (GTK_WIDGET (window), shape, 0, 0);
  ungrab_pointer (gdk_display_get_default (), GTK_WIDGET (window));
#endif	  
  paint_curtain ();
  paint_cross ();
  return TRUE;
}


